package jscinttools.transmission;

import jscinttools.utilities.aidautilities.AidaFactories;
import jscinttools.utilities.aidautilities.AidaFileReader;
import hep.aida.ITree;
import hep.aida.ITreeFactory;
import hep.aida.ITuple;
import hep.aida.ITupleFactory;
import hep.aida.IDataPointSetFactory;
import hep.aida.IDataPointSet;
import java.lang.System;
import java.lang.String;
import java.lang.Double;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import fr.in2p3.ipnl.aidautilities.TupleReader;
import jscinttools.transmission.*;

/**
 *  Calculate the Rates for transmission measurements with TDC
 *
 *@author     Marc-Antoine Verdier
 *@created    19 mai 2011
 */
public class TDCRateLED implements AidaFactories
{
	/**
	 *  Calculate the Rates and the Errors
	 *
	 *@author     Marc-Antoine Verdier
	 *@created    25 mai 2011
	 */
	public interface RateLED
	{
		/**
		 *  Description of the Method
		 *
		 *@param  chanTDC   Description of the Parameter
		 *@param  removeOl  Description of the Parameter
		 *@return           Description of the Return Value
		 */
		public double[] calcRateAndErrSec(int chanTDC, boolean removeOl);


		/**
		 *  Description of the Method
		 *
		 *@param  chanTDC  Description of the Parameter
		 *@return          Description of the Return Value
		 */
		public double[] calcRateAndErrSec(int chanTDC);
	}


	EventLED[] evtLED;
	EventLED[] bckEvtLED;
	ITree tree;


	/**
	 *  Constructor for the TDCRateLED object
	 *
	 *@param  evtLED     Description of the Parameter
	 *@param  bckEvtLED  Description of the Parameter
	 *@param  tree       Description of the Parameter
	 */
	public TDCRateLED(EventLED[] evtLED, EventLED[] bckEvtLED, ITree tree)
	{
		this.evtLED = evtLED;
		this.bckEvtLED = bckEvtLED;
		this.tree = tree;
	}


	/**
	 *  Constructor for the TDCRateLED object
	 *
	 *@param  evtLED     Description of the Parameter
	 *@param  bckEvtLED  Description of the Parameter
	 *@param  tree       Description of the Parameter
	 */
	public TDCRateLED(EventLED[] evtLED, EventLED bckEvtLED, ITree tree)
	{
		this(evtLED, new EventLED[]{bckEvtLED}, tree);
	}


	/**
	 *  Constructor for the TDCRateLED object
	 */
	public TDCRateLED() { }


	/**
	 *  Gets the evtLED attribute of the TDCRateLED object
	 *
	 *@return    The evtLED value
	 */
	public EventLED[] getEvtLED()
	{
		return evtLED;
	}


	/**
	 *  Sets the evtLED attribute of the TDCRateLED object
	 *
	 *@param  evtLED  The new evtLED value
	 */
	public void setEvtLED(EventLED[] evtLED)
	{
		this.evtLED = evtLED;
	}


	/**
	 *  Gets the bckEvtLED attribute of the TDCRateLED object
	 *
	 *@return    The bckEvtLED value
	 */
	public EventLED[] getBckEvtLED()
	{
		return bckEvtLED;
	}


	/**
	 *  Sets the bckEvtLED attribute of the TDCRateLED object
	 *
	 *@param  bckEvtLED  The new bckEvtLED value
	 */
	public void setBckEvtLED(EventLED[] bckEvtLED)
	{
		this.bckEvtLED = bckEvtLED;
	}


	/**
	 *  Gets the tree attribute of the TDCRateLED object
	 *
	 *@return    The tree value
	 */
	public ITree getTree()
	{
		return tree;
	}


	/**
	 *  Sets the tree attribute of the TDCRateLED object
	 *
	 *@param  tree  The new tree value
	 */
	public void setTree(ITree tree)
	{
		this.tree = tree;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  chans       Description of the Parameter
	 *@param  freqHz      Description of the Parameter
	 *@param  splitTerms  Description of the Parameter
	 */
	public void makeTupleAndDPS(int[] chans, double freqHz, String[] splitTerms)
	{
		try
		{
			try
			{
				ITuple stabTup = AidaFactories.ANALYSIS_FACTORY.createTupleFactory(tree).create("AnalysisLED", "AnalysisLED", "double timeMin, double rTransTot, double rTransTotErr, double rRefTot, double rRefTotErr, double rBckTrans, double rBckTransErr, double rBckRef, double rBckRefErr, double rTrans, double rTransErr, double rRef, double rRefErr, double rTransNorm, double rTransNormErr, double rRefNorm, double RefNormErr, double rRatio, double rRatioErr, double rRatioNorm, double rRatioNormErr");
				for (int i = 0; i < evtLED.length; i++)
				{
					RateLED rled = rateLED(new AidaFileReader(evtLED[i].getPath() + File.separator + evtLED[i].getFile().split("_NoH")[0] + "_events").grabTuple(evtLED[i].getFile().split("_NoH")[0] + "_events"), freqHz);
					RateLED rledBck = null;
					if (bckEvtLED.length > 1)
						rledBck = rateLED(new AidaFileReader(bckEvtLED[i].getPath() + File.separator + bckEvtLED[i].getFile().split("_NoH")[0] + "_events").grabTuple(bckEvtLED[i].getFile().split("_NoH")[0] + "_events"), freqHz);
					else if (bckEvtLED.length == 1)
						rledBck = rateLED(new AidaFileReader(bckEvtLED[0].getPath() + File.separator + bckEvtLED[0].getFile().split("_NoH")[0] + "_events").grabTuple(bckEvtLED[0].getFile().split("_NoH")[0] + "_events"), freqHz);
					else
						System.out.println("Problem: no background files");

					stabTup.fill(calcTupColVal(stabTup.columns(), rled, evtLED[i].getFile(), rledBck, chans, splitTerms));
					stabTup.addRow();
				}
				completeTuple(stabTup);

				String[] nameDPS = {"rateTransTot", "rateRefTot", "rateBckTrans", "rateBckRef", "rateTrans"
						, "rateRef", "rateTransNorm", "rateRefNorn", "rateRatio", "rateRatioNorm"};

				IDataPointSetFactory dpsf = AidaFactories.ANALYSIS_FACTORY.createDataPointSetFactory(tree);
				IDataPointSet[] dps = new IDataPointSet[nameDPS.length];

				for (int i = 0; i < nameDPS.length; i++)
				{
					dps[i] = dpsf.create(nameDPS[i], 2);
				}

				for (int i = 0; i < stabTup.rows(); i++)
				{
					stabTup.setRow(i);
					for (int j = 0; j < nameDPS.length; j++)
					{
						dps[j].addPoint();
						dps[j].point(i).coordinate(0).setValue(stabTup.getDouble(0));
						dps[j].point(i).coordinate(1).setValue(stabTup.getDouble((j * 2) + 1));
						dps[j].point(i).coordinate(1).setErrorMinus(stabTup.getDouble((j * 2) + 2));
						dps[j].point(i).coordinate(1).setErrorPlus(stabTup.getDouble((j * 2) + 2));
					}
				}
			} catch (FileNotFoundException fnfe)
			{
				System.out.println(fnfe);
			}
		} catch (IOException ioe)
		{
			System.out.println("Problem with aida file: " + ioe);
		}
	}


	/**
	 *  Description of the Method
	 *
	 *@param  numCol      Description of the Parameter
	 *@param  rled        Description of the Parameter
	 *@param  fileName    Description of the Parameter
	 *@param  rledBck     Description of the Parameter
	 *@param  chans       Description of the Parameter
	 *@param  splitTerms  Description of the Parameter
	 *@return             Description of the Return Value
	 */
	private double[] calcTupColVal(int numCol, RateLED rled, String fileName, RateLED rledBck, int[] chans, String[] splitTerms)
	{
		double[] val = new double[numCol];
		double[] rateValTrans = rled.calcRateAndErrSec(chans[0]);
		double[] rateValRef = rled.calcRateAndErrSec(chans[1]);
		double[] rateValTransBck = rledBck.calcRateAndErrSec(chans[0]);
		double[] rateValRefBck = rledBck.calcRateAndErrSec(chans[1]);
		String tempName = fileName.split(splitTerms[0])[1].split(splitTerms[1])[0];
		double tempVal = 0;
		if (tempName.endsWith("m"))
			tempVal = Double.valueOf(tempName.split("m")[0]) / 1000.0;
		else
			tempVal = Double.valueOf(tempName);
		val[0] = tempVal;
		val[1] = rateValTrans[0];
		val[2] = rateValTrans[1];
		val[3] = rateValRef[0];
		val[4] = rateValRef[1];
		val[5] = rateValTransBck[0];
		val[6] = rateValTransBck[1];
		val[7] = rateValRefBck[0];
		val[8] = rateValRefBck[1];
		val[9] = rateValTrans[0] - rateValTransBck[0];
		val[10] = Math.sqrt(Math.pow(rateValTrans[1], 2) + Math.pow(rateValTransBck[1], 2));
		val[11] = rateValRef[0] - rateValRefBck[0];
		val[12] = Math.sqrt(Math.pow(rateValRef[1], 2) + Math.pow(rateValRefBck[1], 2));
		val[13] = 0;
		val[14] = 0;
		val[15] = 0;
		val[16] = 0;
		val[17] = val[9] / val[11];
		//val[18] = Math.sqrt(Math.pow(val[10] * val[11] / val[9] / val[9], 2) + Math.pow(val[12] / val[9], 2));
		val[18] = Math.sqrt(Math.pow(val[9] * val[12] / val[11] / val[11], 2) + Math.pow(val[10] / val[11], 2));
		val[19] = 0;
		val[20] = 0;
		return val;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  stabTup  Description of the Parameter
	 */
	private void completeTuple(ITuple stabTup)
	{
		stabTup.setRow(0);
		double transScalFac = stabTup.getDouble(9);
		double transScalFacErr = stabTup.getDouble(10);
		double refScalFac = stabTup.getDouble(11);
		double refScalFacErr = stabTup.getDouble(12);
		double ratioScalFac = stabTup.getDouble(17);
		double ratioScalFacErr = stabTup.getDouble(18);

		ITuple cTup = AidaFactories.TUPLE_FACTORY.createCopy("Copy Tuple", stabTup);
		stabTup.reset();
		cTup.start();
		while (cTup.next())
		{
			for (int j = 0; j < cTup.columns(); j++)
			{
				if (j == 13)
					stabTup.fill(j, cTup.getDouble(9) / transScalFac);
				else if (j == 14)
					stabTup.fill(j, Math.sqrt(Math.pow(cTup.getDouble(10) / transScalFac, 2) + Math.pow(cTup.getDouble(9) * transScalFacErr / transScalFac / transScalFac, 2)));
				else if (j == 15)
					stabTup.fill(j, cTup.getDouble(11) / refScalFac);
				else if (j == 16)
					stabTup.fill(j, Math.sqrt(Math.pow(cTup.getDouble(12) / refScalFac, 2) + Math.pow(cTup.getDouble(11) * refScalFacErr / refScalFac / refScalFac, 2)));
				else if (j == 19)
					stabTup.fill(j, cTup.getDouble(17) / ratioScalFac);
				else if (j == 20)
					stabTup.fill(j, Math.sqrt(Math.pow(cTup.getDouble(18) / ratioScalFac, 2) + Math.pow(cTup.getDouble(17) * ratioScalFacErr / ratioScalFac / ratioScalFac, 2)));
				else
					stabTup.fill(j, cTup.getDouble(j));
			}
			stabTup.addRow();
		}
	}


	///**
	// *  Description of the Method
	// *
	// *@param  tuple  Description of the Parameter
	// */
	//public void makeDPS(ITuple tuple)
	//{
	//
	//	String[] nameDPS = {"rateTransTot", "rateRefTot", "rateBckTrans", "rateBckRef", "rateTrans"
	//			, "rateRef", "rateTransNorm", "rateRefNorn", "rateRatio", "rateRatioNorm"};
	//
	//	IDataPointSetFactory dpsf = AidaFactories.ANALYSIS_FACTORY.createDataPointSetFactory(tree);
	//	IDataPointSet[] dps = new IDataPointSet[nameDPS.length];
	//
	//	for (int i = 0; i < nameDPS.length; i++)
	//	{
	//		dps[i] = dpsf.create(nameDPS[i], 2);
	//	}
	//
	//	for (int i = 0; i < tuple.rows(); i++)
	//	{
	//		for (int j = 0; j < nameDPS.length; j++)
	//		{
	//			dps[j].addPoint();
	//			dps[j].point(i).coordinate(0).setValue(tuple.getDouble(0));
	//			dps[j].point(i).coordinate(1).setValue(tuple.getDouble((j * 2) + 1));
	//			dps[j].point(i).coordinate(1).setErrorMinus(tuple.getDouble((j * 2) + 2));
	//			dps[j].point(i).coordinate(1).setErrorPlus(tuple.getDouble((j * 2) + 2));
	//		}
	//	}
	//}


	/**
	 *  Description of the Method
	 *
	 *@param  eventTuple  Description of the Parameter
	 *@param  freqHz      Description of the Parameter
	 *@return             Description of the Return Value
	 */
	public RateLED rateLED(ITuple eventTuple, double freqHz)
	{
		return new ImpRateLED(eventTuple, freqHz);
	}


	/**
	 *  Description of the Class
	 *
	 *@author     Marc-Antoine Verdier
	 *@created    24 mai 2011
	 */
	class ImpRateLED implements RateLED
	{
		ITuple eventTuple;
		double freqHz;


		/**
		 *  Constructor for the RateLED object
		 *
		 *@param  eventTuple  Description of the Parameter
		 *@param  freqHz      Description of the Parameter
		 */
		public ImpRateLED(ITuple eventTuple, double freqHz)
		{
			this.eventTuple = eventTuple;
			this.freqHz = freqHz;
		}


		/**
		 *  Description of the Method
		 *
		 *@param  chanTDC   Description of the Parameter
		 *@param  removeOl  Description of the Parameter
		 *@return           Description of the Return Value
		 */
		public double[] calcRateAndErrSec(int chanTDC, boolean removeOl)
		{
			double phot = 0;
			int evt = 0;
			for (int i = 0; i < eventTuple.rows(); i++)
			{
				eventTuple.setRow(i);
				if (!removeOl)
				{
					phot += eventTuple.getInt(chanTDC + 1);
					evt++;
				}
				else
				{
					if (eventTuple.getInt(1) == 0)
					{
						phot += eventTuple.getInt(chanTDC + 1);
						evt++;
					}
				}
			}
			return new double[]{phot * freqHz / (double) evt, Math.sqrt(phot) * freqHz / (double) evt};
		}


		/**
		 *  Description of the Method
		 *
		 *@param  chanTDC  Description of the Parameter
		 *@return          Description of the Return Value
		 */
		public double[] calcRateAndErrSec(int chanTDC)
		{
			return calcRateAndErrSec(chanTDC, true);
		}
	}
}

